﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections;

namespace PO_2011.Effect
{
    class Effect : BitmapFastPixel
    {
        public static Bitmap makeEffect(Bitmap img, string type, int n = 0)
        {
            old_img = img;
            new_img = new Bitmap(img);
            N = n;

            switch (type)
            {
                case "oil":
                    effectOil();
                    break;
                case "negative":
                    effectNegative();
                    break;
                case "solarisation":
                    effectSolarisation();
                    break;
                case "horizontal":
                    effectHorizontal();
                    break;
                case "bathroom":
                    effectBathroom();
                    break;
                default:
                    break;
            }

            return getNewImage(true);
        }

        private static void effectOil()
        {
            int intensity_levels = 20;

            for (int x = N; x < old_img.Width - N; x++)
            {
                for (int y = N; y < old_img.Height - N; y++)
                {
                    int cur_max = -1, max_index = -1;

                    Hashtable intensity_count = new Hashtable();
                    Hashtable averageR = new Hashtable();
                    Hashtable averageG = new Hashtable();
                    Hashtable averageB = new Hashtable();

                    for (int i = -N; i < N; i++)
                    {
                        for (int j = -N; j < N; j++)
                        {

//                            Color color = old_img.GetPixel(x + i, y + j);
                            int[] color = getFastPixel(x + i, y + j);

                            int cur_intensity = (int)((double)((color[0] + color[1] + color[2]) / 3) * intensity_levels) / 255;

                            if (intensity_count.ContainsKey(cur_intensity))
                            {
                                intensity_count[cur_intensity] = (int) intensity_count[cur_intensity] + 1;
                            }
                            else
                            {
                                intensity_count[cur_intensity] = 1;
                                averageR[cur_intensity] = 0;
                                averageG[cur_intensity] = 0;
                                averageB[cur_intensity] = 0;
                            }

                            averageR[cur_intensity] = (int) averageR[cur_intensity] + color[0];
                            averageG[cur_intensity] = (int) averageG[cur_intensity] + color[1];
                            averageB[cur_intensity] = (int) averageB[cur_intensity] + color[2];



                            if ((int) intensity_count[cur_intensity] > cur_max)
                            {
                                cur_max = (int) intensity_count[cur_intensity];
                                max_index = cur_intensity;
                            }

                        }
                    }
                    
                    setFastPixel(x, y, (int) averageR[max_index] / cur_max, (int) averageG[max_index] / cur_max, (int) averageB[max_index] / cur_max);
                }
            }
        }


        private static void effectNegative()
        {
            for (int x = 0; x < old_img.Width; x++)
            {
                for (int y = 0; y < old_img.Height; y++)
                {
                    int[] color = getFastPixel(x, y);

                    setFastPixel(x, y, 255 - (int)color[0], 255 - (int)color[1], 255 - (int)color[2]);
                }
            }
        }

        private static void effectSolarisation()
        {
            int Z = 255;

            for (int x = 0; x < old_img.Width; x++)
            {
                for (int y = 0; y < old_img.Height; y++)
                {
                    int[] color = getFastPixel(x, y);
                    int r = (color[0] > (Z * x) / (2 * old_img.Width)) ? color[0] : Z - color[0];
                    int g = (color[1] > (Z * x) / (2 * old_img.Width)) ? color[1] : Z - color[1];
                    int b = (color[2] > (Z * x) / (2 * old_img.Width)) ? color[2] : Z - color[2];

                    setFastPixel(x, y, r, g, b);
                }
            }
        }

        // 0 left, 1 right
        private static void effectHorizontal(int side = 0)
        {
            for (int x = 0; x < old_img.Width; x++)
            {
                for (int y = 0; y < old_img.Height; y++)
                {
                    int[] color = getFastPixel(x, y);

                    if (((N == 0) && (x < (old_img.Width / 2))) == true)
                    {
                        color = getFastPixel(old_img.Width - x - 1, y);
                    }
                    else if (( (N == 1) && (x > (old_img.Width / 2)) ) == true)
                    {
                        color = getFastPixel(old_img.Width - x, y);
                    }

                    setFastPixel(x, y, color[0], color[1], color[2]);
                }
            }
        }

        private static void effectBathroom()
        {
            for (int x = 0; x < old_img.Width; x++)
            {
                for (int y = 0; y < old_img.Height; y++)
                {
                    int[] color = getFastPixel(x, y);
                    
                    int a = x > 0 ? (int) Math.Atan(y/x) : 0;

                    int r = (int) Math.Sqrt(x*x + y*y);


                    if (N == 0)
                    {
                        int xx = x + (x % 32) - 16;
                        if (xx > 0 && xx < old_img.Width)
                        {
                            color = getFastPixel(xx, y);
                        }
                    }
                    else
                    {
                        int xx = x + ((a + r / 10) % 32) - 16;
                        if (xx > 0 && xx < old_img.Width)
                        {
                            color = getFastPixel(xx, y);
                        }
                    }

                    setFastPixel(x, y, color[0], color[1], color[2]);
                }
            }
        }

    }
}
